!==============================================================================
! Copyright (C) 2010, University Corporation for Atmospheric Research,
!                     Colorado State University,
!                     Los Alamos National Security, LLC,
!                     United States Department of Energy
!
! All rights reserved.  See ../COPYING for copyright details
!==============================================================================

!>
!! Proxy module for one of the other boundary exchange modules.  The value
!! of boundary_exchange_algorithm will determine which boundary exchange
!! algorithm to use.
!<
module gshalo
    use kinds_mod, only: i4, r8
    use caf_single_pull_halo, only: &
        caf_single_pull_update_1d_dbl_start,  &
        caf_single_pull_update_1d_dbl_finish, &
        caf_single_pull_update_1d_int,        &
        caf_single_pull_init
    use caf_single_push_halo, only:  &
        caf_single_push_update_1d_dbl_start,  &
        caf_single_push_update_1d_dbl_finish, &
        caf_single_push_update_1d_int,        &
        caf_single_push_init
    use constants, only: ALG_MPI2S_1D,ALG_CAF_MULTI_PULL_1D, &
        ALG_CAF_SINGLE_PULL_1D,ALG_CAF_SINGLE_PUSH_1D, &
        boundary_exchange_algorithm

    implicit none
    private

    !>
    !! Routine to perform the boundary exchange operation when local data
    !! is stored in a 1-dimensional array.
    !<
    public :: GSHalo_update_1d_int
    public :: GSHalo_update_1d_dbl_start
    public :: GSHalo_update_1d_dbl_finish

    public :: GSHalo_init

  contains

    !***********************************************************************
    !<
    !! Routine to start the boundary exchange operation when local data
    !! is stored in a 2-dimensional array of reals.
    !!
    !! @param handle  Communication handle (generated by initialization
    !!                routine).
    !! @param array   Local data array; ghost cells are updated on output.
    !>
    subroutine GSHalo_update_1d_dbl_start(handle,array)
        integer(i4), intent(in) :: handle
        real(r8), intent(inout) :: array(:)

        select case (boundary_exchange_algorithm)
            case (ALG_CAF_SINGLE_PULL_1D)
                call caf_single_pull_update_1d_dbl_start(handle, array)
            case (ALG_CAF_SINGLE_PUSH_1D)
                call caf_single_push_update_1d_dbl_start(handle, array)
        end select
    end subroutine GSHalo_update_1d_dbl_start

    !***********************************************************************
    !<
    !! Routine to start the boundary exchange operation when local data
    !! is stored in a 2-dimensional array of reals.
    !!
    !! @param handle  Communication handle (generated by initialization
    !!                routine).
    !! @param array   Local data array; ghost cells are updated on output.
    !>
    subroutine GSHalo_update_1d_dbl_finish(handle,array)
        integer(i4), intent(in) :: handle
        real(r8), intent(inout) :: array(:)

        select case (boundary_exchange_algorithm)
            case (ALG_CAF_SINGLE_PULL_1D)
                call caf_single_pull_update_1d_dbl_finish(handle, array)
            case (ALG_CAF_SINGLE_PUSH_1D)
                call caf_single_push_update_1d_dbl_finish(handle, array)
        end select
    end subroutine GSHalo_update_1d_dbl_finish

    !***********************************************************************
    !<
    !! Routine to finish the boundary exchange operation when local data
    !! is stored in a 2-dimensional array of ints.  This should be called
    !! after calling GSHalo_update_1d_dbl_start and a synchronization routine
    !! should be called inbetween the calls
    !!
    !! @param handle  Communication handle (generated by initialization
    !!                routine).
    !! @param array   Local data array; ghost cells are updated on output.
    !>
    subroutine GSHalo_update_1d_int(handle,array)
        integer(i4), intent(in)    :: handle
        integer(i4), intent(inout) :: array(:)

        select case (boundary_exchange_algorithm)
            case (ALG_CAF_SINGLE_PULL_1D)
                call caf_single_pull_update_1d_int(handle, array)
            case (ALG_CAF_SINGLE_PUSH_1D)
                call caf_single_push_update_1d_int(handle, array)
        end select
    end subroutine GSHalo_update_1d_int

    !***********************************************************************
    !<
    !! Initialize data-structures that are used for the boundary exchange
    !! operation (in other words calculate communication schedule information).
    !! This routine needs to be invoked a single time before making calls
    !! to GSHalo_update.  This function returns a communication handle.
    !!
    !! @param COMM        MPI communicator for proccesses involved in
    !!                    boundary exchange operation.
    !! @param maxlinear   The maximum number of gridpoints in the 1D data
    !!                    structure.
    !! @param nTotal      Total number of gridpoints including active and halo
    !!                    points.
    !! @param nActive     The total number of active ocean gridpoints.
    !! @param LinearGdof  A 1D array which contains the global degrees of
    !!                    freedom for this MPI task.
    !! @param LinearProc  A 1D array which contains the MPI rank or task for
    !!                    each gridpoint.
    !>
    function GSHalo_init(COMM,maxlinear, nTotal,nActive,LinearGdof,LinearProc) &
        result(handle)

        integer(i4), intent(in) :: COMM
        integer(i4), intent(in) :: maxlinear
        integer(i4), intent(in) :: nTotal,nActive
        integer(i4), intent(in) :: LinearGdof(maxlinear)
        integer(i4), intent(in) :: LinearProc(maxlinear)

        integer(i4) :: handle

        select case (boundary_exchange_algorithm)
            case (ALG_CAF_SINGLE_PULL_1D)
                handle =caf_single_pull_init( &
                COMM,maxlinear, nTotal,nActive,LinearGdof,LinearProc)
            case (ALG_CAF_SINGLE_PUSH_1D)
                handle =caf_single_push_init( &
                COMM,maxlinear, nTotal,nActive,LinearGdof,LinearProc)
        end select
    end function GSHalo_init
end module gshalo
